package com.sun.example.recyclerview;

import android.graphics.Rect;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;

import androidx.recyclerview.widget.RecyclerView;

import java.util.ArrayList;
import java.util.List;


/**
 * @author tianxiaolong
 * time：2019-10-05 21:48
 * description：
 */
public class TableLayoutManager extends RecyclerView.LayoutManager {

	private static final String TAG = "TABLE_LayoutManager";
	private static final boolean DEBUG = true;
	private ArrayList<Rect> firstRects;


	public TableLayoutManager(int maxClounms, int firstClounms) {
		this.maxClounms = maxClounms;
		this.firstClounms = firstClounms;
	}

	public TableLayoutManager(int maxClounms) {
		this(maxClounms, maxClounms);
	}

	/**
	 * 最大列数
	 */
	private final int maxClounms;

	/**
	 * 第一行的列数
	 */
	private final int firstClounms;


	private int maxWidth;

	private int firstRectMaxWidth;

	private int firstRectHeight;

	private int maxHeight;

	private int hor = 0;

	private int ver;


	private int vibCount;

	private boolean initData;

	private int itemWidth;

	private int itemHeight;

	@Override
	public RecyclerView.LayoutParams generateDefaultLayoutParams() {
		return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
	}


	@Override
	public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
		if (getItemCount() <= 0 || state.isPreLayout()) {
			if (getItemCount() <= 0) {
				removeAndRecycleAllViews(recycler);
			}
			return;
		}
		final int itemCount = getItemCount();
		logd("itemCount:" + itemCount);
		logd("stateItemCount:" + state.getItemCount());

		initStepRect(recycler);
		detachAndScrapAttachedViews(recycler);
		fill(recycler);


	}

	private void initStepRect(RecyclerView.Recycler recycler) {
		if (firstRects != null) {
			firstRects.clear();
		}
		firstRects = new ArrayList<>(firstClounms);

		int tempOffset = 0;
		for (int i = 0; i < firstClounms; i++) {
			final View view = recycler.getViewForPosition(i);
			addView(view);
			measureChildWithMargins(view, 0, 0);
			int width = getDecoratedMeasuredWidth(view);
			int height = getDecoratedMeasuredHeight(view);
			Rect rect = new Rect(tempOffset, 0, tempOffset + width, height);
			firstRects.add(rect);
			tempOffset += width;
		}
		// init decode rect
		final View viewForPosition = recycler.getViewForPosition(firstClounms);
		addView(viewForPosition);
		measureChildWithMargins(viewForPosition, 0, 0);
		itemWidth = getDecoratedMeasuredWidth(viewForPosition);
		itemHeight = getDecoratedMeasuredHeight(viewForPosition);
		removeAndRecycleAllViews(recycler);

		vibCount = (int) Math.ceil(getVerticalVisibleHeight()*1.0f / firstRects.get(0).height());
		firstRectMaxWidth = tempOffset;
		firstRectHeight = firstRects.get(0).height();
		maxWidth = Math.max(tempOffset, itemWidth * maxClounms);
		maxHeight = (getItemCount() - firstClounms) / maxClounms * itemHeight + itemHeight;
	}

	public int getVerticalVisibleHeight() {
		return getHeight() - getPaddingTop() - getPaddingBottom();
	}


	/**
	 * fill layout
	 * {@link android.widget.ExpandableListView.OnChildClickListener}
	 *
	 * @param recycler
	 */
	private void fill(RecyclerView.Recycler recycler) {
		layoutFirstWidget(recycler);

		layoutChilds(recycler);
		recycleChildren(recycler);
	}

	private int getRowFirstPosition(int rowPosition) {
		int i = rowPosition - firstClounms;
		int remainder = i % maxClounms;
		return rowPosition - remainder;
	}

	private boolean isRowFirstPosition(int rowPosition) {
		int i = rowPosition - firstClounms;
		int remainder = i % maxClounms;
		return remainder == 0;
	}

	private int getChildOffset() {
		int i = -(ver - firstRectHeight);
		if (Math.abs(i) > itemHeight) {
			i = -Math.abs(i) % itemHeight;
		}
		return i;
	}

	private int getChildStartIndex() {
		int childOffset = -(ver - firstRectHeight);
		if (childOffset >= 0) {
			return 0;
		}
		int i = Math.abs(childOffset) / itemHeight;
		return i;
	}

	private void layoutChilds(RecyclerView.Recycler recycler) {
		//这里后面需要改成从后面往前遍历 现在暂时这样

		//start position of row
		int index = hor / itemWidth + firstClounms+1;
		int rowFirstPosition = getRowFirstPosition(index);
		//left offset
		int offset = -hor % itemWidth;
		int top = getChildOffset();
		int maxClounms;
		int countOffset = 0;
		if (top < firstRectHeight) {
			countOffset = 1;
		}
		if (offset < 0) {
			int showWidth = getSpaceWidth() - itemWidth * 2 - offset;
			maxClounms = showWidth / itemWidth + 2;
			if (showWidth % itemWidth > 0) {
				maxClounms += 1;
			}
		} else {
			maxClounms = getSpaceWidth() / itemWidth + 2;
			if (getSpaceWidth() % itemWidth > 0) {
				maxClounms += 1;
			}
		}
		offset += itemWidth;
		int childStartIndex = getChildStartIndex();
		for (int i = childStartIndex; i < vibCount + childStartIndex + countOffset; i++) {
			// current row start index
			int temIndex = i * this.maxClounms + index;
			// current row end index
			int endIndex = temIndex + maxClounms-1;
			int tempChildOffset = offset;
			if (temIndex >= getItemCount()) break;
			if (endIndex >= getItemCount()) {
				endIndex = getItemCount();
			}
			for (int j = temIndex; j < endIndex; j++) {
				if (isRowFirstPosition(j)) continue;
				if (j < 0) continue;
				logd("test position:" + j);
				layoutView(recycler.getViewForPosition(j), tempChildOffset, top, tempChildOffset + itemWidth, top + itemHeight);
				tempChildOffset += itemWidth;
			}
			int firstPosition = rowFirstPosition + i * this.maxClounms;
			layoutView(recycler.getViewForPosition(firstPosition), 0, top, itemWidth, top + itemHeight);
			top += itemHeight;
		}

	}


	/**
	 * @return child offset
	 */
	private void layoutFirstWidget(RecyclerView.Recycler recycler) {
		if (hor >= firstRectMaxWidth - firstRects.get(0).width()) return;
		if (ver >= firstRectHeight) return;
		int startIndex = 0;
		int tempOffset = 0;
		int firstWidgetOffset = 0;
		for (int i = 1; i < firstRects.size(); i++) {
			Rect it = firstRects.get(i);
			tempOffset += it.width();
			// slide past i num widget
			if (tempOffset == hor) {
				startIndex = i + 1;
				break;
			}

			if (tempOffset > hor) {
				firstWidgetOffset = -(it.width() - (tempOffset - hor));
				startIndex = i;
				break;
			}
		}
		firstWidgetOffset += firstRects.get(0).width();

		int width = firstRects.get(0).width();
		int top = -ver;
		for (int i = startIndex; i < firstRects.size(); i++) {
			Rect it = firstRects.get(i);
			int left = firstWidgetOffset;
			int right = firstWidgetOffset + it.width();
			layoutView(recycler.getViewForPosition(i), left, top, right, top + it.height());
			if (startIndex==i) {
				width += right-firstRects.get(0).width();
			} else {
				width += it.width();
			}
			firstWidgetOffset += it.width();
			if (width >= getSpaceWidth()) {
				logd("layout firstWidth break index:" + i);
				break;
			}
		}

		Rect rect = firstRects.get(0);
		layoutView(recycler.getViewForPosition(0), 0, top, rect.width(), top + rect.height());


	}

	private void recycleChildren(RecyclerView.Recycler recycler) {
		List<RecyclerView.ViewHolder> scrapList = recycler.getScrapList();
		for (int i = 0; i < scrapList.size(); i++) {
			RecyclerView.ViewHolder holder = scrapList.get(i);
			removeView(holder.itemView);
			recycler.recycleView(holder.itemView);
		}
	}

	private void layoutView(View view, int left, int top, int right, int bottom) {
		addView(view);
		measureChildWithMargins(view, 0, 0);
		layoutDecorated(view, left, top, right, bottom);
	}


	@Override
	public boolean canScrollHorizontally() {
		return true;
	}

	@Override
	public boolean canScrollVertically() {
		return true;
	}

	/**
	 * 从右往左 正
	 * 从左往右 负
	 *
	 * @param dx
	 * @param recycler
	 * @param state
	 * @return
	 */
	@Override
	public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
		logd("dx:" + dx);
//		int trayel = dx;
//		if(hor+ dx < 0){
//			trayel = -hor;
//		}else if(hor+dx > maxWidth - getSpaceWidth()){
//			trayel = maxWidth - hor - getSpaceWidth();
//		}
//		hor+=trayel;
		int trayel = requestHorizontallyBy(dx);
		detachAndScrapAttachedViews(recycler);
		fill(recycler);
		logd("hor trayel:" + trayel);
		logd("hor offset:" + hor);
		return trayel;
	}


	@Override
	public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
		int travel = requestVerVerticallyBy(dy);
		detachAndScrapAttachedViews(recycler);
		fill(recycler);
		return travel;
	}

	private int requestVerVerticallyBy(int dy) {
		int travel = dy;
		//如果滑动到最顶部
		if (ver + dy < 0) {
			travel = -ver;
			//如果滑动到底部
		} else if (ver + dy > maxHeight - getVerticalSpace()) {
			travel = maxHeight - getVerticalSpace() - ver;
		}
		ver += travel;
		logd("ver:" + ver);
		return travel;
	}

	private int requestHorizontallyBy(int dx) {
		if (maxWidth <= getSpaceWidth()) return 0;
		int trayel = dx;
		if (hor + dx < 0) {
			trayel = -hor;
		} else if (hor + dx > maxWidth - getSpaceWidth()) {
			trayel = maxWidth - hor - getSpaceWidth();
		}
		hor += trayel;
		return trayel;
	}

	private int getSpaceWidth() {
		return getWidth() - getPaddingLeft() - getPaddingRight();
	}

	private int getVerticalSpace() {
		return getHeight() - getPaddingBottom() - getPaddingTop();
	}

	private void logd(String msg) {
		if (DEBUG) Log.d(TAG, msg);

	}

}
